#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

#include "mi_sys.h"

#include "mi_panel_datatype.h"
#include "mi_panel.h"
#include "mi_disp_datatype.h"
#include "mi_disp.h"

#include "sstarFb.h"

#ifdef CC0702I50R
#include "CC0702I50R_1024x600.h"
#endif

#ifdef FRD720X720BK
#include "FRD720x720BK_MIPI.h"
#endif

#define MAKE_YUYV_VALUE(y,u,v)  ((y) << 24) | ((u) << 16) | ((y) << 8) | (v)
#define YUYV_BLACK              MAKE_YUYV_VALUE(0,128,128)

#if defined(__cplusplus)||defined(c_plusplus)
extern "C"{
#endif

#define FB_PATH	"/dev/fb0"

static MI_DISP_PubAttr_t stDispPubAttr;

int sstar_disp_init(MI_DISP_PubAttr_t *pstDispPubAttr)
{
    MI_PANEL_LinkType_e eLinkType;
    MI_DISP_InputPortAttr_t stInputPortAttr;

    memset(&stInputPortAttr, 0, sizeof(stInputPortAttr));

    MI_SYS_Init();

    if (pstDispPubAttr->eIntfType == E_MI_DISP_INTF_LCD)
    {
        pstDispPubAttr->stSyncInfo.u16Vact = stPanelParam.u16Height;
        pstDispPubAttr->stSyncInfo.u16Vbb = stPanelParam.u16VSyncBackPorch;
        pstDispPubAttr->stSyncInfo.u16Vfb = stPanelParam.u16VTotal - (stPanelParam.u16VSyncWidth +
                                                                      stPanelParam.u16Height + stPanelParam.u16VSyncBackPorch);
        pstDispPubAttr->stSyncInfo.u16Hact = stPanelParam.u16Width;
        pstDispPubAttr->stSyncInfo.u16Hbb = stPanelParam.u16HSyncBackPorch;
        pstDispPubAttr->stSyncInfo.u16Hfb = stPanelParam.u16HTotal - (stPanelParam.u16HSyncWidth +
                                                                      stPanelParam.u16Width + stPanelParam.u16HSyncBackPorch);
        pstDispPubAttr->stSyncInfo.u16Bvact = 0;
        pstDispPubAttr->stSyncInfo.u16Bvbb = 0;
        pstDispPubAttr->stSyncInfo.u16Bvfb = 0;
        pstDispPubAttr->stSyncInfo.u16Hpw = stPanelParam.u16HSyncWidth;
        pstDispPubAttr->stSyncInfo.u16Vpw = stPanelParam.u16VSyncWidth;
        pstDispPubAttr->stSyncInfo.u32FrameRate = stPanelParam.u16DCLK * 1000000 / (stPanelParam.u16HTotal * stPanelParam.u16VTotal);
        pstDispPubAttr->eIntfSync = E_MI_DISP_OUTPUT_USER;
        pstDispPubAttr->eIntfType = E_MI_DISP_INTF_LCD;
		pstDispPubAttr->u32BgColor = YUYV_BLACK;
		eLinkType = stPanelParam.eLinkType;
    }

    stInputPortAttr.u16SrcWidth = stPanelParam.u16Width;
    stInputPortAttr.u16SrcHeight = stPanelParam.u16Height;
    stInputPortAttr.stDispWin.u16X = 0;
    stInputPortAttr.stDispWin.u16Y = 0;
    stInputPortAttr.stDispWin.u16Width = stPanelParam.u16Width;
    stInputPortAttr.stDispWin.u16Height = stPanelParam.u16Height;

    //printf("DISP width: %d,height: %d\n",stInputPortAttr.stDispWin.u16Width,stInputPortAttr.stDispWin.u16Height);

    MI_DISP_SetPubAttr(0, pstDispPubAttr);
    MI_DISP_Enable(0);
    MI_DISP_BindVideoLayer(0, 0);
    MI_DISP_EnableVideoLayer(0);

    MI_DISP_SetInputPortAttr(0, 0, &stInputPortAttr);
    MI_DISP_EnableInputPort(0, 0);
    MI_DISP_SetInputPortSyncMode(0, 0, E_MI_DISP_SYNC_MODE_FREE_RUN);

    if (pstDispPubAttr->eIntfType == E_MI_DISP_INTF_LCD)
    {
        MI_PANEL_Init(eLinkType);
        MI_PANEL_SetPanelParam(&stPanelParam);
        if(eLinkType == E_MI_PNL_LINK_MIPI_DSI)
        {
            MI_PANEL_SetMipiDsiConfig(&stMipiDsiConfig);
        }
    }

    return 0;
}

int sstar_disp_deinit(MI_DISP_PubAttr_t *pstDispPubAttr)
{

    MI_DISP_DisableInputPort(0, 0);
    MI_DISP_DisableVideoLayer(0);
    MI_DISP_UnBindVideoLayer(0, 0);
    MI_DISP_Disable(0);

    switch(pstDispPubAttr->eIntfType) {
        case E_MI_DISP_INTF_HDMI:
            break;

        case E_MI_DISP_INTF_VGA:
            break;

        case E_MI_DISP_INTF_LCD:
        default:
            MI_PANEL_DeInit();

    }

    MI_SYS_Exit();

    return 0;
}

static void sstar_handle_signal(int signo)
{
    sstar_disp_deinit(&stDispPubAttr);
}

static void sstar_setup_signals(void)
{
    struct sigaction s;

    memset(&s, 0, sizeof(s));
    s.sa_handler = sstar_handle_signal;
    s.sa_flags = 0;
    sigaction(SIGTERM, &s, NULL);

    s.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &s, NULL);
}

int main(void)
{
	int fb = -1;
	struct fb_var_screeninfo vinfo;
	stDispPubAttr.eIntfType = E_MI_DISP_INTF_LCD;
	stDispPubAttr.eIntfSync = E_MI_DISP_OUTPUT_USER;

	sstar_setup_signals();

	sstar_disp_init(&stDispPubAttr);

	fb = open(FB_PATH, O_RDWR);

	if (fb < 0) {
		perror("open fb error");
		goto err_out;
	}

	if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == -1) {
		perror("Error reading variable information");
		goto err_out;
	}

	ioctl(fb, FBIOPAN_DISPLAY, &vinfo);

	pause();

err_out:
	if (fb > 0) {
		close(fb);
	}
	sstar_disp_deinit(&stDispPubAttr);

	return 0;
}

#if defined(__cplusplus)||defined(c_plusplus)
}
#endif

